#include "myserver.h"

bool isupdate = false;
bool update_ready = false;
bool update_all = false;

MyServer::MyServer()
{
    if(!GetConfig())exit(1);
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(listen_ipAddress.c_str());
    server_addr.sin_port = htons(listen_port);
    // create socket to listen
    listen_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(listen_fd < 0)
    {
        perror("Create Socket Failed.");
        exit(1);
    }
    int opt = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    update_ready = false;
    update_file_size = 0;
    update_all = false;
}

MyServer::~MyServer()
{
    free(ep_events);
}

bool MyServer::GetConfig()
{
    ifstream ifs("/root/config.ini");
    if(!ifs.is_open())
    {
        cout<<"未找到配置文件，请检查/root/config.ini文件是否存在\n";
        return false;
    }
    string str;
    getline(ifs,str);
    getline(ifs,listen_ipAddress);
    cout<<"Listen IP: "<<listen_ipAddress<<endl;
    getline(ifs,str);
    getline(ifs,str);
    listen_port = static_cast<uint16_t>(stoi(str));
    cout<<"Listen Port: "<<listen_port<<endl;
    ifs.close();
    return true;
}

void MyServer::Bind()
{
    if(-1 == (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))
    {
        perror("Server Bind Failed.");
        exit(1);
    }
    cout << "Bind Successfully.\n";
}

void MyServer::Listen(int num)
{
    if(-1 == listen(listen_fd, num))
    {
        perror("Server Listen Failed.");
        exit(1);
    }
    cout << "Listen Successfully.\n";
}

void MyServer::Accept()
{
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    int new_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_addr_len);
    if(new_fd < 0)
    {
        perror("Server Accept Failed.");
        exit(1);
    }

    string ip(inet_ntoa(client_addr.sin_addr));    // 获取客户端IP

    SetNoBlockMode(new_fd);
    event.events = EPOLLIN|EPOLLET;
    event.data.fd = new_fd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&event);
    mmap.insert(make_pair(new_fd, make_pair(ip, 0)));

    cout << "IP: "<<ip<<" PORT:"<<client_addr.sin_port<<"的远程设备连接到服务器\n";
}

void MyServer::Recv(int sockfd)
{
    int readLen = 0;
    while(1)
    {
        PACKET_HEAD ph;
        readLen = read(sockfd,&ph,sizeof(ph));
        if(readLen == 0)
        {
            epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
            close(sockfd);
            cout<<"client close,IP: "<<mmap[sockfd].first<<"\n";
            mmap.erase(sockfd);
            break;
        }
        else if(readLen < 0 && errno == EAGAIN)break;
        else
        {
            if(ph.type == HEART)
            {
                mmap[sockfd].second = 0;
                cout<<"recv heart pack. IP:"<<mmap[sockfd].first<<"\n";
            }
            else if(ph.type == OTHER)
            {
                int readSize = ph.length;
                char* buff = new char[readSize];
                int recvsize = 0,currecvsize = 0;
                while(recvsize < readSize)
                {
                    currecvsize = read(sockfd,buff + recvsize,readSize - recvsize);
                    if(currecvsize == 0)
                    {
                        epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
                        close(sockfd);
                        cout<<"client close,IP: "<<mmap[sockfd].first<<"\n";
                        mmap.erase(sockfd);
                        break;
                    }
                    else if(currecvsize < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN))
                        break;//暂时没数据可读
                    else if(currecvsize < 0 && errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN)//error
                    {
                        perror("read error");
                        break;
                    }
                    recvsize += currecvsize;
                }
                delete[]buff;
            }
            break;
        }
    }
}

void MyServer::Run()
{
    pthread_t id,id2,id3;     // 创建心跳检测线程
    int ret = pthread_create(&id, NULL, heart_handler, (void*)this);
    if(ret != 0)
    {
        perror("Can not create heart_handler thread.");
        exit(1);
    }
    ret = pthread_create(&id2, NULL, http_handler, (void*)this);
    if(ret != 0)
    {
        perror("Can not create http_handler thread");
        exit(1);
    }
    ret = pthread_create(&id3, NULL, update_handler, (void*)this);
    if(ret != 0)
    {
        perror("Can not create update_handler thread.");
        exit(1);
    }

    epfd = epoll_create(EPOLL_SIZE);
    ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
    SetNoBlockMode(listen_fd);
    event.events = EPOLLIN|EPOLLET;
    event.data.fd = listen_fd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&event);

    while(1)
    {
        ev_count = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);
        if(ev_count == -1 && errno != EINTR)
        {
            perror("epoll_wait error.");
            break;
        }
        printf("ev_count = %d\n",ev_count);
        for(int i = 0; i < ev_count; ++i)
        {
            if(ep_events[i].data.fd == listen_fd)
            {
                Accept();
            }
            else
            {
                Recv(ep_events[i].data.fd);
            }
        }
    }
    close(listen_fd);
    close(epfd);
}

void MyServer::SetNoBlockMode(int sock)
{
    if(sock == -1)
    {
        printf("SetNoBlockMode error:socket描述符为-1\n");
        return;
    }
    int flag = fcntl(sock,F_GETFL,0);
    fcntl(sock,F_SETFL,flag | O_NONBLOCK);
}

void MyServer::GetUpdateFileSize()
{
    int fd = open("/root/mau",O_RDONLY);
    if(fd!=-1)
    {
       struct stat buf;
       fstat(fd,&buf);
       update_file_size = buf.st_size;
       close(fd);
    }
    else
    {
        cout<<"/root/mau下未找到升级文件\n";
    }
}

void MyServer::SendUpdateSignalToAll()
{
    map<int, pair<string, uint8_t> >::iterator it = mmap.begin();
    for( ; it!=mmap.end(); )
    {
        int len = write(it->first,&update_file_size,sizeof(update_file_size));
        if(len == -1)
            perror("write error:");
        if(len != sizeof(update_file_size))
            cout<<"数据丢失\n";
        ++it;
    }
}

void* heart_handler(void* arg)
{
    cout<<"heart-beat thread start\n";
    MyServer* ser = (MyServer*)arg;
    while(1)
    {
        map<int, pair<string, uint8_t> >::iterator it = ser->mmap.begin();
        for( ; it!=ser->mmap.end(); )
        {
            if(it->second.second == 5)//判定为客户端断开连接
            {
                epoll_ctl(ser->epfd,EPOLL_CTL_DEL,it->first,NULL);
                close(it->first);
                cout<<"client close,IP: "<<it->second.first<<"\n";
                ser->mmap.erase(it++);
            }
            else if(it->second.second < 5 && it->second.second >= 0)
            {
                it->second.second += 1;
                ++it;
            }
            else
            {
                ++it;
            }
        }
        sleep(30);
    }
}

void* http_handler(void* arg)
{
    cout<<"http server thread start\n";
    httplib::Server svr;
    svr.Get("/",handle_get_index);
    svr.Get("/get_update_file",handle_get_getfile);
    svr.Get("/get_update_state",handle_get_update_state);
    svr.Post("/upload_update_file",handle_post_upload_update_file);
    svr.Post("/update",handle_post_update);
    svr.Post("/update_state",handle_post_update_state);
    svr.listen("0.0.0.0",8080);
}

void handle_get_index(const httplib::Request& req, httplib::Response& res)
{
    ifstream file("/root/upload_script.html", ios::in | ios::binary);
    if (!file) {
        res.status = 404;
        res.set_content("upload_script.html not found.", "text/plain");
        return;
    }

    // 将文件内容读入内存
    stringstream buffer;
    buffer << file.rdbuf();
    file.close();

    // 设置响应头
    res.status = 200;
    res.set_content(buffer.str(), "text/html");
}

void handle_get_getfile(const httplib::Request& req, httplib::Response& res)
{
    ifstream file("/root/mau", ios::in|ios::binary);
    if (!file) {
        res.status = 404;
        res.set_content("update file not found.", "text/plain");
        return;
    }

    // 将文件内容读入内存
    stringstream buffer;
    buffer << file.rdbuf();
    file.close();
    // 设置响应头
    res.status = 200;
    res.set_content(buffer.str(), "text/html");
}

void handle_post_upload_update_file(const httplib::Request& req, httplib::Response& res)
{
    auto fileMultipart = req.get_file_value("file");
    auto nameMultipart = req.get_file_value("name");
    auto passwordMultipart = req.get_file_value("password");
    auto fileSizeMultipart = req.get_file_value("fileSize");
    int fileSize = std::stoi(fileSizeMultipart.content);
    string name = nameMultipart.content;
    string password = passwordMultipart.content;
    if (name=="root"&&password=="root")
    {
        auto filename = fileMultipart.filename;
        auto content_type = fileMultipart.content_type;
        int len = static_cast<int>(fileMultipart.content.size());
        printf("收到升级包, 文件名: %s  文件大小: %d 实际文件大小: %d 流类型: %s\n",filename.c_str(),fileSize,
               len,content_type.c_str());
        //if(LOG==1)zlog_info(c,"收到升级包,文件名: %s 文件大小: %d 实际文件大小: %d 流类型: %s",
            //filename.c_str(),fileSize,len,content_type.c_str());
        if(len != fileSize)
        {
            res.status = 403;
            printf("文件传输过程中损坏,请重试.\n");
//            res.set_content("文件传输过程中损坏或给出的文件大小值不对,请重试.", "text/plain");
            //if(LOG==1)zlog_info(c,"文件传输过程中损坏或给出的文件大小值不对,请重试.");
            return;
        }
        filename = "/root/" + filename;
        printf("filename = %s\n",filename.c_str());
        // 打开文件准备写入
        FILE* fp = fopen(filename.c_str(),"wb");
        if (fp)
        {
            fwrite(fileMultipart.content.c_str(),1,len,fp);
            fflush(fp);
            fclose(fp);
            res.status = 200;
            printf("保存升级包成功.\n");
//            res.set_content("升级包上传成功", "text/plain");
        }
        else
        {
            res.status = 500;
//            res.set_content("保存升级包失败,请重试", "text/plain");
            perror("升级包保存失败,请重试\n");
            //if(LOG==1)zlog_info(c,"升级包保存失败,请重试.");
        }
    }
    else
    {
        res.status = 401;
        printf("用户名或密码错误.\n");
//        res.set_content("请检查参数,确保文件参数是mau,文件大小参数是filesize", "text/plain");
    }
}

void handle_post_update(const httplib::Request& req, httplib::Response& res)
{
    update_ready = true;
    auto var = req.get_file_value("update_all");
    if(var.name == "update_all")
        update_all = true;
    else
        update_all = false;
    res.status=200;
    res.body="success";
}

void handle_get_update_state(const httplib::Request& req, httplib::Response& res)
{
    if(isupdate)
    {
        res.status = 200;
    }
    else
    {
        res.status = 202;
    }
}

void handle_post_update_state(const httplib::Request& req, httplib::Response& res)
{
    if(req.body=="success")
        isupdate = true;
    else
        isupdate = false;
    res.status = 200;
}

void* update_handler(void* arg)
{
    cout<<"update thread start\n";
    MyServer* ser = (MyServer*)arg;
    while(1)
    {
        if(update_ready)
        {
            ser->GetUpdateFileSize();
            if(update_all)
            {
                ser->SendUpdateSignalToAll();
            }
            else//向特定设备发送升级信号
            {

            }
            update_ready = 0;
        }
        sleep(3);
    }
}
